package nz.jdbcwrapper;

import java.sql.SQLException;
import java.sql.Ref;
import java.sql.PreparedStatement;

import java.util.Map;

class WrapperRef implements Ref
{
  final Ref ref;
  final String prefix;
  final long id = Util.id();
  final Data data;
  final Statistic statistic;

  WrapperRef(Data data, Statistic statistic, Ref ref, String parentPrefix)
  {
    this.data = data;
    this.statistic = statistic;
    this.ref = ref;
    prefix = parentPrefix + "[" + id + "]";
  }

  /**
   * Retrieves the fully-qualified SQL name of the SQL structured type that
   * this <code>Ref</code> object references.
   *
   * @return the fully-qualified SQL name of the referenced SQL structured type
   * @exception SQLException if a database access error occurs
   * @since 1.2
   */
  public String getBaseTypeName() throws SQLException
  {
    long key = 0L;

    if (data.trace >= 5)
      key = Util.traceBegin(prefix + " getBaseTypeName()");

    long duration = Long.MIN_VALUE;
    long start = 0L;
    SQLException excp;

    try
    {
      start = System.currentTimeMillis();
      String result = ref.getBaseTypeName();
      duration = System.currentTimeMillis() - start;

      if (data.trace >= 5)
        Util.traceEnd(key, result);

      return result;
    }
    catch (SQLException e)
    {
      duration = System.currentTimeMillis() - start;
      if (data.trace >= 5)
        Util.traceEnd(key, e);

      excp = e;
    }
    finally
    {
      if (duration == Long.MIN_VALUE)
        duration = System.currentTimeMillis() - start;
      statistic.column(duration);
    }

    throw excp;
  }


  /**
   * Retrieves the referenced object and maps it to a Java type
   * using the given type map.
   *
   * @param map a <code>java.util.Map</code> object that contains
   *        the mapping to use (the fully-qualified name of the SQL
   *        structured type being referenced and the class object for
   *        <code>SQLData</code> implementation to which the SQL
   *        structured type will be mapped)
   * @return  a Java <code>Object</code> that is the custom mapping for
   *          the SQL structured type to which this <code>Ref</code>
   *          object refers
   * @exception SQLException if a database access error occurs
   * @since 1.4
   * @see #setObject
   */
  public Object getObject(Map map) throws SQLException
  {
    long key = 0L;
    if (data.trace >= 6)
      key = Util.traceBegin(prefix + " getObject(Map)");

    long duration = Long.MIN_VALUE;

    long start = 0L;
    SQLException excp;

    try
    {
      start = System.currentTimeMillis();
      Object result = ref.getObject(map);
      duration = System.currentTimeMillis() - start;

      if (data.trace >= 6)
        Util.traceEnd(key, Util.toString(result));
      return result;
    }
    catch (SQLException e)
    {
      if (data.trace >= 6)
        Util.traceEnd(key, e);
      excp = e;
    }
    finally
    {
      if (duration == Long.MIN_VALUE)
        duration = System.currentTimeMillis() - start;
      statistic.column(duration);
    }
    throw excp;
  }

  /**
   * Retrieves the SQL structured type instance referenced by
   * this <code>Ref</code> object.  If the connection's type map has an entry
   * for the structured type, the instance will be custom mapped to
   * the Java class indicated in the type map.  Otherwise, the
   * structured type instance will be mapped to a <code>Struct</code> object.
   *
   * @return  a Java <code>Object</code> that is the mapping for
   *          the SQL structured type to which this <code>Ref</code>
   *          object refers
   * @exception SQLException if a database access error occurs
   * @since 1.4
   * @see #setObject
   */
  public Object getObject() throws SQLException
  {
    long key = 0L;
    if (data.trace >= 6)
      key = Util.traceBegin(prefix + " getObject()");

    long duration = Long.MIN_VALUE;

    long start = 0L;
    SQLException excp;

    try
    {
      start = System.currentTimeMillis();
      Object result = ref.getObject();
      duration = System.currentTimeMillis() - start;

      if (data.trace >= 6)
        Util.traceEnd(key, Util.toString(result));
      return result;
    }
    catch (SQLException e)
    {
      if (data.trace >= 6)
        Util.traceEnd(key, e);
      excp = e;
    }
    finally
    {
      if (duration == Long.MIN_VALUE)
        duration = System.currentTimeMillis() - start;
      statistic.column(duration);
    }
    throw excp;
  }

  /**
   * Sets the structured type value that this <code>Ref</code>
   * object references to the given instance of <code>Object</code>.
   * The driver converts this to an SQL structured type when it
   * sends it to the database.
   *
   * @param x an <code>Object</code> representing the SQL
   *        structured type instance that this
   *        <code>Ref</code> object will reference
   * @exception SQLException if a database access error occurs
   * @since 1.4
   * @see #getObject()
   * @see #getObject(Map)
   * @see PreparedStatement#setObject(int, Object)
   */
  public void setObject(Object x) throws SQLException
  {
    long key = 0L;
    if (data.trace >= 4)
      key = Util.traceBegin(prefix + " setObject(" +
                            (x == null ? "null" : x.getClass().getName()) + ")");

    try
    {
      ref.setObject(x);
      if (data.trace >= 4)
        Util.traceEnd(key, (String)null);
    }
    catch (SQLException e)
    {
      if (data.trace >= 4)
        Util.traceEnd(key, e);
      throw e;
    }
  }


}
